local
    fun MLListToScheme ([h], t') = Pair (h,t')
      | MLListToScheme (h::t,t') = Pair (h, MLListToScheme (t,t'))
      | MLListToScheme ([], t') = Pair(Nil, t') ;

    fun sexprToString'(Void) = "'void"
      | sexprToString'(Nil) = "()"
      | sexprToString'(Number(n)) =
	if n>=0 then Int.toString(n) else ("-" ^ (Int.toString(~n)))
      | sexprToString'(Char(#" ")) = "#\\space"
      | sexprToString'(Char(#"\t")) = "#\\tab"
      | sexprToString'(Char(#"\n")) = "#\\newline"
      | sexprToString'(Char(#"\r")) = "#\\return"
      | sexprToString'(Char(ch)) =
	if (ch > #" ") then "#\\" ^ Char.toString(ch)
	else let val n = ord(ch)
		 val o3 = n mod 8
		 val tmp = n div 8
		 val o2 = tmp mod 8
		 val o1 = tmp div 8
	     in
		 "#\\" ^
		 Int.toString(o1) ^
		 Int.toString(o2) ^
		 Int.toString(o3)
	     end
      | sexprToString'(Bool(true)) = "#t"
      | sexprToString'(Bool(false)) = "#f"
      | sexprToString'(String(str)) = "\"" ^ str ^ "\""
      | sexprToString'(Symbol(name)) = name
      | sexprToString'(Pair(Symbol("quote"),
			    Pair(e, Nil))) = "'" ^ sexprToString'(e)
      | sexprToString'(Pair(car, cdr)) = toStringWithCar(sexprToString'(car), cdr)
      | sexprToString'(Vector(s)) =
	"#(" ^ (String.concatWith " " (map sexprToString' s)) ^ ")"
    and toStringWithCar(car, Nil) = "(" ^ car ^ ")"
      | toStringWithCar(car, Pair(first, second)) =
	toStringWithCar(car ^ " " ^ sexprToString'(first), second)
      | toStringWithCar(car, e) = "(" ^ car ^ " . " ^ sexprToString'(e) ^ ")" ;

    fun sexprToString(Void) = ""
      | sexprToString(e) = sexprToString'(e) ;


    fun exprToSexpr (Const Void) = exprToSexpr (Const (Symbol "void")) (* #<void> is unreadable *)
    |	exprToSexpr (Const (e as Number(_))) = e
    |	exprToSexpr (Const (e as Char(_))) = e
    |	exprToSexpr (Const (e as Bool(_))) = e
      | exprToSexpr (Const const) = MLListToScheme ([Symbol "quote", const], Nil)
      | exprToSexpr (Var name) = Symbol name
      | exprToSexpr (VarFree name) = exprToSexpr (Var name)
      | exprToSexpr (VarParam (name,_)) = exprToSexpr (Var name)
      | exprToSexpr (VarBound (name,_,_)) = exprToSexpr (Var name)
      | exprToSexpr (If (if', then', else')) =
	MLListToScheme ((Symbol "if")::(List.map exprToSexpr [if', then', else']), Nil)
      | exprToSexpr (Abs ([], body)) = MLListToScheme ([Symbol "lambda", Nil, exprToSexpr body], Nil)
      | exprToSexpr (Abs (args, body)) =
	MLListToScheme ([Symbol "lambda", MLListToScheme (List.map Symbol args, Nil), exprToSexpr body], Nil)
      | exprToSexpr (AbsOpt ([], arg', body)) = exprToSexpr(AbsVar(arg', body))
      | exprToSexpr (AbsOpt (args, arg', body)) =
	MLListToScheme ([Symbol "lambda",
			MLListToScheme ((List.map Symbol args),Symbol arg'), exprToSexpr body], Nil)
      | exprToSexpr (AbsVar (arg,body)) =
	MLListToScheme ([Symbol "lambda", Symbol arg, exprToSexpr body], Nil)
      | exprToSexpr (App (f, args)) =
	MLListToScheme (List.map exprToSexpr (f::args), Nil)
      | exprToSexpr (AppTP (x as (f, args))) = exprToSexpr (App x)
      | exprToSexpr (Seq exprs) =
	MLListToScheme ((Symbol "begin")::(List.map exprToSexpr exprs), Nil)
      | exprToSexpr (Or exprs) =
	MLListToScheme ((Symbol "or")::(List.map exprToSexpr exprs), Nil)
      | exprToSexpr (Set (n,v)) =
	MLListToScheme ([(Symbol "set!"),exprToSexpr n, exprToSexpr v], Nil)
      | exprToSexpr (Def (n,v)) =
	MLListToScheme ([(Symbol "define"),exprToSexpr n, exprToSexpr v], Nil) ;
in fun unparse e = sexprToString (exprToSexpr e) end

